<template>
  <div class="view-xhr">
    <div class="view-options">
      <div class="options-start">
        <el-input placeholder="请输入地址" v-model="request.url.raw" class="input-with-select">
          <el-select v-model="request.method" slot="prepend" placeholder="请选择">
            <el-option
              v-for="item in methodList"
              :key="item.text"
              :label="item.text"
              :value="item.value"></el-option>
          </el-select>
        </el-input>
      </div>
      <div class="options-end">
        <el-dropdown split-button type="primary" @click="handleSend">
          发送
          <el-dropdown-menu slot="dropdown">
            <el-dropdown-item>下载</el-dropdown-item>
          </el-dropdown-menu>
        </el-dropdown>
      </div>
    </div>
    <div class="panel-title">请求参数</div>
    <div class="view-panel">
      <el-tabs v-model="activeTab" @tab-click="handleChangeTab">
        <el-tab-pane :label="tabs[0].text" name="first">
          <ParamsView v-model="request.url.query" :columns="keyValueCatbaseColumns">
            <template v-slot:head-start>{{ dataTitle }}</template>
          </ParamsView>
        </el-tab-pane>
        <el-tab-pane :label="tabs[1].text" name="second">
          <BodyView v-model="request.body">
            <template v-slot:head-start>{{ dataTitle }}</template>
          </BodyView>
        </el-tab-pane>
        <el-tab-pane :label="tabs[2].text" name="third">
          <ParamsView v-model="request.header">
            <template v-slot:head-start>{{ dataTitle }}</template>
          </ParamsView>
        </el-tab-pane>
        <el-tab-pane :label="tabs[3].text" name="fourth">
          <ParamsView v-model="request.cookie">
            <template v-slot:head-start>{{ dataTitle }}</template>
          </ParamsView>
        </el-tab-pane>
        <el-tab-pane :label="tabs[4].text" name="fifth">
          <SettingView></SettingView>
        </el-tab-pane>
      </el-tabs>
    </div>
  </div>
</template>

<script>
import { DS, fetchService, objecter } from '@daelui/dogjs/dist/components.js'
import ParamsView from '../data/params.vue'
import BodyView from './body.vue'
import SettingView from './setting.vue'
import interfaceTpl from '../constant/interface.js'
import keyValueCatbaseColumns from '../constant/key-value-catbase-columns.js'
import utils from '../data/utils.js'

// 初始化服务
const ds = new DS()
ds.service = fetchService

export default {
  components: {
    ParamsView,
    BodyView,
    SettingView
  },

  props: {
    value: {
      default () {
        return objecter.clone(interfaceTpl)
      }
    }
  },

  computed: {
    request () {
      return this.value.request
    }
  },

  data() {
    return {
      keyValueCatbaseColumns,
      methodList: [
        { text: 'GET', value: 'GET' },
        { text: 'POST', value: 'POST' },
        { text: 'PUT', value: 'PUT' },
        { text: 'DELETE', value: 'DELETE' },
        { text: 'PATCH', value: 'PATCH' },
        { text: 'HEAD', value: 'HEAD' },
        { text: 'OPTIONS', value: 'OPTIONS' }
      ],
      tabs: [
        {text: 'Params', value: 'first'},
        {text: 'Body', value: 'second'},
        {text: 'Headers', value: 'third'},
        {text: 'Cookie', value: 'fourth'},
        {text: '设置', value: 'fifth'}
      ],
      activeTab: 'first',
      dataTitle: '',
      typeValue: 'keyvalue'
    }
  },

  beforeMount () {
    this.handleChangeTab()
  },

  methods: {
    // 切换页签
    handleChangeTab(){
      let activeTab = this.activeTab
      let node = this.tabs.find(item => item.value === activeTab)|| {}
      this.dataTitle = node.text
    },
    // 发送数据
    handleSend () {
      let request = this.format(this.value.request)
      if (!request.url) {
        this.$message({
          type: 'warning',
          message: '请输入请求地址'
        })
        return true
      }
      ds.request({
        method: request.method,
        url: request.url,
        query: request.query,
        data: request.data,
        headers: request.headers,
        solveResultData (res) {
          return res
        }
      }).then(res => {
        let response = this.value.response[0]
        let headers = []
        try {
          if (res.xhr) {
            let str = res.xhr.getAllResponseHeaders()
            str.split('\n').forEach(function(row) {
              if (!row) {
                return true
              }
              let index = row.indexOf(':')
              headers.push({
                key: row.slice(0, index),
                value: row.slice(index + 1).trim(),
                type: 'string',
                required: true
              })
            })
          } else if (res.response) {
            let h = res.response.headers
            Array.from(h.keys()).forEach(key => {
              headers.push({
                key: key,
                value: h.get(key),
                type: 'string',
                required: true
              })
            })
          }
        } catch (e) {
          headers = []
        }
        let node = {
          code: res.status,
          status: res.statusText,
          header: headers,
          body: res.responseText,
          timestamp: res.timestamp
        }
        if (!response) {
          response = node
          this.value.response.examples.push(response)
        }
        Object.assign(response, node)
      })
    },
    // 格式化
    format (request) {
      request = utils.pureRequest(request)
      let options = {}
      options.method = request.method.toLowerCase()
      options.url = request.url.raw
      // 参数
      let query = {}
      request.url.query.forEach(item => {
        query[item.key] = item.value
      })
      options.query = query
      // 内容
      let body = null, mode = request.body.mode
      if (/formdata/.test(mode)) {
        if (request.body.formdataValue.length) {
          body = new FormData()
          request.body.formdataValue.forEach(item => {
            let val = item.value
            if (typeof val === 'object' && val.raw) {
              body.append(item.key, val.raw)
            } else {
              body.append(item.key, utils.formatValue(val, item.type))
            }
          })
        }
      } else if (/urlencoded/.test(mode)) {
        if (request.body.urlencodedValue.length) {
          body = {}
          request.body.urlencodedValue.forEach(item => {
            body[item.key] = utils.formatValue(item.value, item.type)
          })
        }
        // 请求头
        let ctype = 'application/x-www-form-urlencoded;charset=UTF-8'
        request.header.unshift({ key: 'Content-Type', value: ctype })
      } else if (/raw/.test(mode)) {
        body = /^\s*$/.test(request.body.rawValue) ? null : request.body.rawValue
        // 请求头
        let lang = request.body.options.raw.language, ctype = 'application/json;charset=UTF-8'
        if (lang === 'text') {
          ctype = 'text/plain;charset=UTF-8'
        } else if (lang === 'json') {
          ctype = 'application/json;charset=UTF-8'
        } else if (lang === 'html') {
          ctype = 'text/html;charset=UTF-8'
        } else if (lang === 'xml') {
          ctype = 'application/xml;charset=UTF-8'
        } else if (lang === 'javascript') {
          ctype = 'application/javascript;charset=UTF-8'
        }
        request.header.unshift({ key: 'Content-Type', value: ctype })
      } else if (/file/.test(mode)) {
        let ctype = 'application/octet-stream'
        request.header.unshift({ key: 'Content-Type', value: ctype })
        let val = request.body.fileValue
        if (typeof val === 'object' && val.raw) {
          body = val.raw
        } else {
          body = null
        }
      } else {
        body = null
      }
      options.data = body
      // 请求头
      this.adaptHeaders(options, request)

      return options
    },
    // 格式化头
    adaptHeaders (options, request) {
      let cookie = request.cookie, clist = []
      cookie.forEach(item => {
        let key = String(item.key).trim(), val = String(item.value).trim()
        if (key) {
          clist.push(encodeURIComponent(key) + '=' + encodeURIComponent(val))
        }
      })
      let headers = {}, cookieKey, map = {}
      request.header.forEach(item => {
        let key = String(item.key).trim(), val = String(item.value).trim()
        let lkey = key.toLowerCase()
        if (key && val && !map[lkey]) {
          headers[key] = val
          map[lkey] = true
        }
        if (/cookie/i.test(key)) {
          cookieKey = key
        }
      })
      let cookieValue = headers[cookieKey]
      if (cookieValue) {
        clist.push(cookieValue)
      }
      if (clist.length) {
        headers[cookieKey || 'Cookie'] = clist.join(';')
      }

      options.headers = headers
    }
  }
}
</script>

<style lang="less" scoped>
.view-options {
  display: flex;
  justify-content: space-between;
  align-items: center;
  .options-start {
    flex: 1;
    /deep/.el-select .el-input {
      width: 120px;
      input {
        font-weight: 700;
        color: #333;
      }
    }
  }
  .options-end {
    padding-left: 8px;
  }
}
.panel-title {
  padding-top: 8px;
  font-weight: 700;
  color: #666;
  font-style: italic;
}
.view-panel {
  /deep/.el-tabs__header {
    margin-bottom: 8px;
  }
}
</style>